package com.jichangxiu.common.utils;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.jichangxiu.common.constant.Constants;
import com.jichangxiu.common.entity.bo.Record;
import org.springframework.util.StreamUtils;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Iterator;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

public class ServletUtils {

    public static void setInfoToRequest(String key, Object value) {
        setInfoToRequest(getRequest(), key, value);
    }

    public static void setInfoToRequest(HttpServletRequest httpServletRequest, String key, Object value) {
        httpServletRequest.setAttribute(key, value);
    }

    public static String getStrFromRequest(String key) {
        return getStrFromRequest(getRequest(), key);
    }

    public static String getStrFromRequest(HttpServletRequest httpServletRequest, String key) {
        Object object = httpServletRequest.getAttribute(key);
        return ObjectUtil.isEmpty(object) ? null : String.valueOf(object);
    }

    public static <T> T getInfoFromRequest(String key, Class<T> cs) {
        Object object = getInfoFromRequest(ServletUtils.getRequest(), key);
        return ObjectUtil.isEmpty(object) ? null : ObjUtils.getValueByClass(object, cs);
    }


    public static <T> T getInfoFromRequest(HttpServletRequest httpServletRequest, String key, Class<T> cs) {
        Object object = getInfoFromRequest(httpServletRequest, key);
        return ObjectUtil.isEmpty(object) ? null : ObjUtils.getValueByClass(object, cs);
    }

    public static Object getInfoFromRequest(HttpServletRequest httpServletRequest, String key) {
        Object object = httpServletRequest.getAttribute(key);
        return ObjectUtil.isEmpty(object) ? null : object;
    }

    public static String getPath() {
        return getRequest().getServletPath();
    }

    public static String getParameter(String name) {
        return getRequest().getParameter(name);
    }

    public static String getParameter(String name, String defaultValue) {
        HttpServletRequest request = getRequest();
        return ObjectUtil.isNotNull(request) ? Convert.toStr(request.getParameter(name), defaultValue) : defaultValue;
    }

    public static Integer getParameterToInt(String name) {
        return Convert.toInt(getRequest().getParameter(name));
    }

    public static Integer getParameterToInt(String name, Integer defaultValue) {
        return Convert.toInt(getRequest().getParameter(name), defaultValue);
    }

    public static ServletRequestAttributes getRequestAttributes() {
        RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
        return (ServletRequestAttributes) attributes;
    }

    public static Boolean getParameterToBoolean(String name) {
        return Convert.toBool(getRequest().getParameter(name));
    }

    public static Boolean getParameterToBoolean(String name, Boolean defaultValue) {
        return Convert.toBool(getRequest().getParameter(name), defaultValue);
    }

    public static HttpServletRequest getRequest() {
        ServletRequestAttributes requestAttributes = getRequestAttributes();
        return ObjectUtil.isNotNull(requestAttributes) ? requestAttributes.getRequest() : null;
    }

    public static HttpServletResponse getResponse() {
        return getRequestAttributes().getResponse();
    }

    public static HttpSession getSession() {
        return getRequest().getSession();
    }

    public static void renderString(HttpServletResponse response, String string) {
        try {
            response.setStatus(HttpServletResponse.SC_OK);
            response.setContentType("application/json");
            response.setCharacterEncoding("utf-8");
            response.getWriter().print(string);
        } catch (IOException ex) {
            throw new RuntimeException("【Servlet-Utils】渲染字符串异常", ex);
        }
    }

    public static String urlEncode(String str) {
        try {
            return URLEncoder.encode(str, Constants.UTF_8);
        } catch (UnsupportedEncodingException e) {
            return StrUtil.EMPTY;
        }
    }

    public static String urlDecode(String str) {
        try {
            return URLDecoder.decode(str, Constants.UTF_8);
        } catch (UnsupportedEncodingException e) {
            return StrUtil.EMPTY;
        }
    }

    public static boolean isAjaxRequest(HttpServletRequest request) {
        String accept = request.getHeader("accept");
        if (accept != null && accept.contains("application/json"))
            return true;
        String xRequestedWith = request.getHeader("X-Requested-With");
        if (xRequestedWith != null && xRequestedWith.contains("XMLHttpRequest"))
            return true;
        String uri = request.getRequestURI();
        if (StrUtil.equalsAnyIgnoreCase(uri, ".json", ".xml"))
            return true;
        String ajax = request.getParameter("__ajax");
        return StrUtil.equalsAnyIgnoreCase(ajax, "json", "xml");
    }

    public static ConcurrentMap<String, String> getParameter(HttpServletRequest request) {
        ConcurrentMap<String, String> mapParameter = new ConcurrentHashMap<>();
        String method = request.getMethod();
        if ("GET".equalsIgnoreCase(method)) {
            Iterator<Map.Entry<String, String[]>> itr = request.getParameterMap().entrySet().iterator();
            Map.Entry<String, String[]> entry;
            StringBuilder params = new StringBuilder();
            while (itr.hasNext()) {
                entry = itr.next();
                String value = entry.getValue()[0];
                mapParameter.put(entry.getKey(), value);
                String key = entry.getKey();
                if (params.toString().isEmpty())
                    params.append(key).append("=").append(value);
                else
                    params.append("&").append(key).append("=").append(value);
            }
        } else {
            try (InputStream inputStream = request.getInputStream()) {
                String body = StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);
                Record param = JSONUtil.toBean(body, Record.class, true);
                if (Objects.isNull(param) || param.isEmpty())
                    return mapParameter;
                for (Map.Entry<String, Object> entry : param.entrySet())
                    mapParameter.put(entry.getKey(), String.valueOf(entry.getValue()));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return mapParameter;
    }

    public static String getRequestUri() {
        return ServletUtils.getRequest().getRequestURI();
    }

}
